<!DOCTYPE html>
<html>
  <head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
  <meta name="description" content="刘清政">
  <meta name="keyword" content="hexo-theme">
  
    <link rel="shortcut icon" href="/css/images/logo.png">
  
  <title>
    
      go/2-Go语言基础/30-错误处理 | Justin-刘清政的博客
    
  </title>
  <link href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <link href="//cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.css" rel="stylesheet">
  <link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/tomorrow.min.css" rel="stylesheet">
  
<link rel="stylesheet" href="/css/style.css">

  
    
<link rel="stylesheet" href="/css/plugins/gitment.css">

  
  <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/geopattern/1.2.3/js/geopattern.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.js"></script>
  
    
<script src="/js/qrious.js"></script>

  
  
    
<script src="/js/gitment.js"></script>

  
  

  
<meta name="generator" content="Hexo 4.2.0"></head>
<div class="wechat-share">
  <img src="/css/images/logo.png" />
</div>

  <body>
    <header class="header fixed-header">
  <div class="header-container">
    <a class="home-link" href="/">
      <div class="logo"></div>
      <span>Justin-刘清政的博客</span>
    </a>
    <ul class="right-list">
      
        <li class="list-item">
          
            <a href="/" class="item-link">主页</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/tags/" class="item-link">标签</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/archives/" class="item-link">归档</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/about/" class="item-link">关于我</a>
          
        </li>
      
    </ul>
    <div class="menu">
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
    </div>
    <div class="menu-mask">
      <ul class="menu-list">
        
          <li class="menu-item">
            
              <a href="/" class="menu-link">主页</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/tags/" class="menu-link">标签</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/archives/" class="menu-link">归档</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/about/" class="menu-link">关于我</a>
            
          </li>
        
      </ul>
    </div>
  </div>
</header>

    <div id="article-banner">
  <h2>go/2-Go语言基础/30-错误处理</h2>



  <p class="post-date">2019-08-01</p>
    <!-- 不蒜子统计 -->
    <span id="busuanzi_container_page_pv" style='display:none' class="">
        <i class="icon-smile icon"></i> 阅读数：<span id="busuanzi_value_page_pv"></span>次
    </span>
  <div class="arrow-down">
    <a href="javascript:;"></a>
  </div>
</div>
<main class="app-body flex-box">
  <!-- Article START -->
  <article class="post-article">
    <section class="markdown-content"><hr>
<p>title: “30-错误处理 “<br>date: 2019-03-10 08:08<br>tags:</p>
<ul>
<li>Go</li>
</ul>
<hr>
<h2 id="什么是错误？"><a href="#什么是错误？" class="headerlink" title="什么是错误？"></a>什么是错误？</h2><p>错误表示程序中出现了异常情况。比如当我们试图打开一个文件时，文件系统里却并没有这个文件。这就是异常情况，它用一个错误来表示。</p>
<p>在 Go 中，错误一直是很常见的。错误用内建的 <code>error</code> 类型来表示。</p>
<p>就像其他的内建类型（如 <code>int</code>、<code>float64</code> 等），错误值可以存储在变量里、作为函数的返回值等等。</p>
<h2 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h2><p>现在我们开始编写一个示例，该程序试图打开一个并不存在的文件。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (  </span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">    <span class="string">"os"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;  </span><br><span class="line">    f, err := os.Open(<span class="string">"/test.txt"</span>)</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        fmt.Println(err)</span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">    &#125;</span><br><span class="line">    fmt.Println(f.Name(), <span class="string">"opened successfully"</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在程序的第 9 行，我们试图打开路径为 <code>/test.txt</code> 的文件。<code>os</code> 包里的 [<code>Open</code>]函数有如下签名：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Open</span><span class="params">(name <span class="keyword">string</span>)</span> <span class="params">(file *File, err error)</span></span></span><br></pre></td></tr></table></figure>

<p><strong>如果成功打开文件，Open 函数会返回一个文件句柄（File Handler）和一个值为 nil 的错误。而如果打开文件时发生了错误，会返回一个不等于 nil 的错误</strong>。</p>
<p>如果一个[函数] 或[方法] 返回了错误，按照惯例，错误会作为最后一个值返回。于是 <code>Open</code> 函数也是将 <code>err</code> 作为最后一个返回值。</p>
<p><strong>按照 Go 的惯例，在处理错误时，通常都是将返回的错误与 nil 比较。nil 值表示了没有错误发生，而非 nil 值表示出现了错误</strong>。在这里，我们第 10 行检查了错误值是否为 <code>nil</code>。如果不是 <code>nil</code>，我们会简单地打印出错误，并在 <code>main</code> 函数中返回。</p>
<p>运行该程序会输出：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">open &#x2F;test.txt: No such file or directory</span><br></pre></td></tr></table></figure>

<p>很棒！我们得到了一个错误，它指出该文件并不存在。</p>
<h2 id="错误类型的表示"><a href="#错误类型的表示" class="headerlink" title="错误类型的表示"></a>错误类型的表示</h2><p>让我们进一步深入，理解 <code>error</code> 类型是如何定义的。<code>error</code> 是一个[接口]类型，定义如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> error <span class="keyword">interface</span> &#123;  </span><br><span class="line">    Error() <span class="keyword">string</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>error</code> 有了一个签名为 <code>Error() string</code> 的方法。所有实现该接口的类型都可以当作一个错误类型。<code>Error()</code> 方法给出了错误的描述。</p>
<p><code>fmt.Println</code> 在打印错误时，会在内部调用 <code>Error() string</code> 方法来得到该错误的描述。上一节示例中的第 11 行，就是这样打印出错误的描述的。</p>
<h2 id="从错误获取更多信息的不同方法"><a href="#从错误获取更多信息的不同方法" class="headerlink" title="从错误获取更多信息的不同方法"></a>从错误获取更多信息的不同方法</h2><p>现在，我们知道了 <code>error</code> 是一个接口类型，让我们看看如何从一个错误获取更多信息。</p>
<p>在前面的示例里，我们只是打印出错误的描述。如果我们想知道这个错误的文件路径，该怎么做呢？一种选择是直接解析错误的字符串。这是前面示例的输出：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">open &#x2F;test.txt: No such file or directory</span><br></pre></td></tr></table></figure>

<p><strong>我们解析了这条错误信息，虽然获取了发生错误的文件路径，但是这种方法很不优雅。随着语言版本的更新，这条错误的描述随时都有可能变化，使我们程序出错</strong>。</p>
<p>有没有更加可靠的方法来获取文件名呢？答案是肯定的，这是可以做到的，Go 标准库给出了各种提取错误相关信息的方法。我们一个个来看看吧。</p>
<h3 id="1-断言底层结构体类型，使用结构体字段获取更多信息"><a href="#1-断言底层结构体类型，使用结构体字段获取更多信息" class="headerlink" title="1. 断言底层结构体类型，使用结构体字段获取更多信息"></a>1. 断言底层结构体类型，使用结构体字段获取更多信息</h3><p>如果你仔细阅读了 [<code>Open</code>] 函数的文档，你可以看见它返回的错误类型是 <code>*PathError</code>。[<code>PathError</code>]是[结构体]类型，它在标准库中的实现如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> PathError <span class="keyword">struct</span> &#123;  </span><br><span class="line">    Op   <span class="keyword">string</span></span><br><span class="line">    Path <span class="keyword">string</span></span><br><span class="line">    Err  error</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(e *PathError)</span> <span class="title">Error</span><span class="params">()</span> <span class="title">string</span></span> &#123; <span class="keyword">return</span> e.Op + <span class="string">" "</span> + e.Path + <span class="string">": "</span> + e.Err.Error() &#125;</span><br></pre></td></tr></table></figure>

<p>通过上面的代码，你就知道了 <code>*PathError</code> 通过声明 <code>Error() string</code> 方法，实现了 <code>error</code> 接口。<code>Error() string</code> 将文件操作、路径和实际错误拼接，并返回该字符串。于是我们得到该错误信息：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">open &#x2F;test.txt: No such file or directory</span><br></pre></td></tr></table></figure>

<p>结构体 <code>PathError</code> 的 <code>Path</code> 字段，就有导致错误的文件路径。我们修改前面写的程序，打印出该路径。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (  </span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">    <span class="string">"os"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;  </span><br><span class="line">    f, err := os.Open(<span class="string">"/test.txt"</span>)</span><br><span class="line">    <span class="keyword">if</span> err, ok := err.(*os.PathError); ok &#123;</span><br><span class="line">        fmt.Println(<span class="string">"File at path"</span>, err.Path, <span class="string">"failed to open"</span>)</span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">    &#125;</span><br><span class="line">    fmt.Println(f.Name(), <span class="string">"opened successfully"</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上面的程序里，我们在第 10 行使用了[类型断言]（Type Assertion）来获取 <code>error</code> 接口的底层值（Underlying Value）。接下来在第 11 行，我们使用 <code>err.Path</code> 来打印该路径。该程序会输出：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">File at path &#x2F;test.txt failed to open</span><br></pre></td></tr></table></figure>

<p>很棒！我们已经使用类型断言成功获取到了该错误的文件路径。</p>
<h3 id="2-断言底层结构体类型，调用方法获取更多信息"><a href="#2-断言底层结构体类型，调用方法获取更多信息" class="headerlink" title="2. 断言底层结构体类型，调用方法获取更多信息"></a>2. 断言底层结构体类型，调用方法获取更多信息</h3><p>第二种获取更多错误信息的方法，也是对底层类型进行断言，然后通过调用该结构体类型的方法，来获取更多的信息。</p>
<p>我们通过一个实例来理解这一点。</p>
<p>标准库中的 <code>DNSError</code> 结构体类型定义如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> DNSError <span class="keyword">struct</span> &#123;  </span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(e *DNSError)</span> <span class="title">Error</span><span class="params">()</span> <span class="title">string</span></span> &#123;  </span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(e *DNSError)</span> <span class="title">Timeout</span><span class="params">()</span> <span class="title">bool</span></span> &#123;  </span><br><span class="line">    ... </span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(e *DNSError)</span> <span class="title">Temporary</span><span class="params">()</span> <span class="title">bool</span></span> &#123;  </span><br><span class="line">    ... </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>从上述代码可以看到，<code>DNSError</code> 结构体还有 <code>Timeout() bool</code> 和 <code>Temporary() bool</code> 两个方法，它们返回一个布尔值，指出该错误是由超时引起的，还是临时性错误。</p>
<p>接下来我们编写一个程序，断言 <code>*DNSError</code> 类型，并调用这些方法来确定该错误是临时性错误，还是由超时导致的。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (  </span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">    <span class="string">"net"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;  </span><br><span class="line">    addr, err := net.LookupHost(<span class="string">"golangbot123.com"</span>)</span><br><span class="line">    <span class="keyword">if</span> err, ok := err.(*net.DNSError); ok &#123;</span><br><span class="line">        <span class="keyword">if</span> err.Timeout() &#123;</span><br><span class="line">            fmt.Println(<span class="string">"operation timed out"</span>)</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> err.Temporary() &#123;</span><br><span class="line">            fmt.Println(<span class="string">"temporary error"</span>)</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            fmt.Println(<span class="string">"generic error: "</span>, err)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">    &#125;</span><br><span class="line">    fmt.Println(addr)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上述程序中，我们在第 9 行，试图获取 <code>golangbot123.com</code>（无效的域名） 的 ip。在第 10 行，我们通过 <code>*net.DNSError</code> 的类型断言，获取到了错误的底层值。接下来的第 11 行和第 13 行，我们分别检查了该错误是由超时引起的，还是一个临时性错误。</p>
<p>在本例中，我们的错误既不是临时性错误，也不是由超时引起的，因此该程序输出：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">generic error:  lookup golangbot123.com: no such host</span><br></pre></td></tr></table></figure>

<p>如果该错误是临时性错误，或是由超时引发的，那么对应的 if 语句会执行，于是我们就可以适当地处理它们。</p>
<h3 id="3-直接比较"><a href="#3-直接比较" class="headerlink" title="3. 直接比较"></a>3. 直接比较</h3><p>第三种获取错误的更多信息的方式，是与 <code>error</code> 类型的变量直接比较。我们通过一个示例来理解。</p>
<p><code>filepath</code> 包中的 [<code>Glob</code>] 用于返回满足 glob 模式的所有文件名。如果模式写的不对，该函数会返回一个错误 <code>ErrBadPattern</code>。</p>
<p><code>filepath</code> 包中的 <code>ErrBadPattern</code> 定义如下：</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> ErrBadPattern = errors.New(<span class="string">"syntax error in pattern"</span>)</span><br></pre></td></tr></table></figure>

<p><code>errors.New()</code> 用于创建一个新的错误。我们会在下一教程中详细讨论它。</p>
<p>当模式不正确时，<code>Glob</code> 函数会返回 <code>ErrBadPattern</code>。</p>
<p>我们来写一个小程序来看看这个错误。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (  </span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">    <span class="string">"path/filepath"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;  </span><br><span class="line">    files, error := filepath.Glob(<span class="string">"["</span>)</span><br><span class="line">    <span class="keyword">if</span> error != <span class="literal">nil</span> &amp;&amp; error == filepath.ErrBadPattern &#123;</span><br><span class="line">        fmt.Println(error)</span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">    &#125;</span><br><span class="line">    fmt.Println(<span class="string">"matched files"</span>, files)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上述程序里，我们查询了模式为 <code>[</code> 的文件，然而这个模式写的不正确。我们检查了该错误是否为 <code>nil</code>。为了获取该错误的更多信息，我们在第 10 行将 <code>error</code> 直接与 <code>filepath.ErrBadPattern</code> 相比较。如果该条件满足，那么该错误就是由模式错误导致的。该程序会输出：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">syntax error in pattern</span><br></pre></td></tr></table></figure>

<p>标准库在提供错误的详细信息时，使用到了上述提到的三种方法。在下一教程里，我们会通过这些方法来创建我们自己的自定义错误。</p>
<h2 id="不可忽略错误"><a href="#不可忽略错误" class="headerlink" title="不可忽略错误"></a>不可忽略错误</h2><p>绝不要忽略错误。忽视错误会带来问题。接下来我重写上面的示例，在列出所有满足模式的文件名时，我省略了错误处理的代码。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (  </span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">    <span class="string">"path/filepath"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;  </span><br><span class="line">    files, _ := filepath.Glob(<span class="string">"["</span>)</span><br><span class="line">    fmt.Println(<span class="string">"matched files"</span>, files)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>我们已经从前面的示例知道了这个模式是错误的。在第 9 行，通过使用 <code>_</code> 空白标识符，我忽略了 <code>Glob</code> 函数返回的错误。我在第 10 行简单打印了所有匹配的文件。该程序会输出：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">matched files []</span><br></pre></td></tr></table></figure>

<p>由于我忽略了错误，输出看起来就像是没有任何匹配了 glob 模式的文件，但实际上这是因为模式的写法不对。所以绝不要忽略错误。</p>
<p>本教程到此结束。</p>
<p>这一教程我们讨论了该如何处理程序中出现的错误，也讨论了如何查询关于错误的更多信息。简单概括一下本教程讨论的内容：</p>
<ul>
<li>什么是错误？</li>
<li>错误的表示</li>
<li>获取错误详细信息的各种方法</li>
<li>不能忽视错误</li>
</ul>
</section>
    <!-- Tags START -->
    
    <!-- Tags END -->
    <!-- NAV START -->
    
  <div class="nav-container">
    <!-- reverse left and right to put prev and next in a more logic postition -->
    
      <a class="nav-left" href="/go/2-Go%E8%AF%AD%E8%A8%80%E5%9F%BA%E7%A1%80/28-%E5%A4%9A%E6%80%81/">
        <span class="nav-arrow">← </span>
        
          go/2-Go语言基础/28-多态
        
      </a>
    
    
      <a class="nav-right" href="/python/%E8%B7%AF%E9%A3%9E%E9%A1%B9%E7%9B%AE/1-%E9%A1%B9%E7%9B%AE%E5%9F%BA%E7%A1%80/1-pip%E6%BA%90/">
        
          python/路飞项目/1-项目基础/1-pip源
        
        <span class="nav-arrow"> →</span>
      </a>
    
  </div>

    <!-- NAV END -->
    <!-- 打赏 START -->
    
      <div class="money-like">
        <div class="reward-btn">
          赏
          <span class="money-code">
            <span class="alipay-code">
              <div class="code-image"></div>
              <b>使用支付宝打赏</b>
            </span>
            <span class="wechat-code">
              <div class="code-image"></div>
              <b>使用微信打赏</b>
            </span>
          </span>
        </div>
        <p class="notice">点击上方按钮,请我喝杯咖啡！</p>
      </div>
    
    <!-- 打赏 END -->
    <!-- 二维码 START -->
    
      <div class="qrcode">
        <canvas id="share-qrcode"></canvas>
        <p class="notice">扫描二维码，分享此文章</p>
      </div>
    
    <!-- 二维码 END -->
    
      <!-- Gitment START -->
      <div id="comments"></div>
      <!-- Gitment END -->
    
  </article>
  <!-- Article END -->
  <!-- Catalog START -->
  
    <aside class="catalog-container">
  <div class="toc-main">
  <!-- 不蒜子统计 -->
    <strong class="toc-title">目录</strong>
    
      <ol class="toc-nav"><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#什么是错误？"><span class="toc-nav-text">什么是错误？</span></a></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#示例"><span class="toc-nav-text">示例</span></a></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#错误类型的表示"><span class="toc-nav-text">错误类型的表示</span></a></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#从错误获取更多信息的不同方法"><span class="toc-nav-text">从错误获取更多信息的不同方法</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-断言底层结构体类型，使用结构体字段获取更多信息"><span class="toc-nav-text">1. 断言底层结构体类型，使用结构体字段获取更多信息</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#2-断言底层结构体类型，调用方法获取更多信息"><span class="toc-nav-text">2. 断言底层结构体类型，调用方法获取更多信息</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#3-直接比较"><span class="toc-nav-text">3. 直接比较</span></a></li></ol></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#不可忽略错误"><span class="toc-nav-text">不可忽略错误</span></a></li></ol>
    
  </div>
</aside>
  
  <!-- Catalog END -->
</main>

<script>
  (function () {
    var url = 'http://www.liuqingzheng.top/go/2-Go语言基础/30-错误处理/';
    var banner = ''
    if (banner !== '' && banner !== 'undefined' && banner !== 'null') {
      $('#article-banner').css({
        'background-image': 'url(' + banner + ')'
      })
    } else {
      $('#article-banner').geopattern(url)
    }
    $('.header').removeClass('fixed-header')

    // error image
    $(".markdown-content img").on('error', function() {
      $(this).attr('src', 'http://file.muyutech.com/error-img.png')
      $(this).css({
        'cursor': 'default'
      })
    })

    // zoom image
    $(".markdown-content img").on('click', function() {
      var src = $(this).attr('src')
      if (src !== 'http://file.muyutech.com/error-img.png') {
        var imageW = $(this).width()
        var imageH = $(this).height()

        var zoom = ($(window).width() * 0.95 / imageW).toFixed(2)
        zoom = zoom < 1 ? 1 : zoom
        zoom = zoom > 2 ? 2 : zoom
        var transY = (($(window).height() - imageH) / 2).toFixed(2)

        $('body').append('<div class="image-view-wrap"><div class="image-view-inner"><img src="'+ src +'" /></div></div>')
        $('.image-view-wrap').addClass('wrap-active')
        $('.image-view-wrap img').css({
          'width': `${imageW}`,
          'transform': `translate3d(0, ${transY}px, 0) scale3d(${zoom}, ${zoom}, 1)`
        })
        $('html').css('overflow', 'hidden')

        $('.image-view-wrap').on('click', function() {
          $(this).remove()
          $('html').attr('style', '')
        })
      }
    })
  })();
</script>


  <script>
    var qr = new QRious({
      element: document.getElementById('share-qrcode'),
      value: document.location.href
    });
  </script>



  <script>
    var gitmentConfig = "liuqingzheng";
    if (gitmentConfig !== 'undefined') {
      var gitment = new Gitment({
        id: "go/2-Go语言基础/30-错误处理",
        owner: "liuqingzheng",
        repo: "FuckBlog",
        oauth: {
          client_id: "32a4076431cf39d0ecea",
          client_secret: "94484bd79b3346a949acb2fda3c8a76ce16990c6"
        },
        theme: {
          render(state, instance) {
            const container = document.createElement('div')
            container.lang = "en-US"
            container.className = 'gitment-container gitment-root-container'
            container.appendChild(instance.renderHeader(state, instance))
            container.appendChild(instance.renderEditor(state, instance))
            container.appendChild(instance.renderComments(state, instance))
            container.appendChild(instance.renderFooter(state, instance))
            return container;
          }
        }
      })
      gitment.render(document.getElementById('comments'))
    }
  </script>




    <div class="scroll-top">
  <span class="arrow-icon"></span>
</div>
    <footer class="app-footer">
<!-- 不蒜子统计 -->
<span id="busuanzi_container_site_pv">
     本站总访问量<span id="busuanzi_value_site_pv"></span>次
</span>
<span class="post-meta-divider">|</span>
<span id="busuanzi_container_site_uv" style='display:none'>
     本站访客数<span id="busuanzi_value_site_uv"></span>人
</span>
<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>



  <p class="copyright">
    &copy; 2021 | Proudly powered by <a href="https://www.cnblogs.com/xiaoyuanqujing" target="_blank">小猿取经</a>
    <br>
    Theme by <a href="https://www.cnblogs.com/xiaoyuanqujing" target="_blank" rel="noopener">小猿取经</a>
  </p>
</footer>

<script>
  function async(u, c) {
    var d = document, t = 'script',
      o = d.createElement(t),
      s = d.getElementsByTagName(t)[0];
    o.src = u;
    if (c) { o.addEventListener('load', function (e) { c(null, e); }, false); }
    s.parentNode.insertBefore(o, s);
  }
</script>
<script>
  async("//cdnjs.cloudflare.com/ajax/libs/fastclick/1.0.6/fastclick.min.js", function(){
    FastClick.attach(document.body);
  })
</script>

<script>
  var hasLine = 'true';
  async("//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js", function(){
    $('figure pre').each(function(i, block) {
      var figure = $(this).parents('figure');
      if (hasLine === 'false') {
        figure.find('.gutter').hide();
      }
      var lang = figure.attr('class').split(' ')[1] || 'code';
      var codeHtml = $(this).html();
      var codeTag = document.createElement('code');
      codeTag.className = lang;
      codeTag.innerHTML = codeHtml;
      $(this).attr('class', '').empty().html(codeTag);
      figure.attr('data-lang', lang.toUpperCase());
      hljs.highlightBlock(block);
    });
  })
</script>





<!-- Baidu Tongji -->

<script>
    var _baId = 'c5fd96eee1193585be191f318c3fa725';
    // Originial
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "//hm.baidu.com/hm.js?" + _baId;
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
</script>


<script src="/js/script.js"></script>


<script src="/js/search.js"></script>


<script src="/js/load.js"></script>



  <span class="local-search local-search-google local-search-plugin" style="right: 50px;top: 70px;;position:absolute;z-index:2;">
      <input type="search" placeholder="站内搜索" id="local-search-input" class="local-search-input-cls" style="">
      <div id="local-search-result" class="local-search-result-cls"></div>
  </span>


  </body>
</html>